/*
 * Copyright 2011 Michele Mancioppi [michele.mancioppi@gmail.com]
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cave.nice.testMessage.resources;

import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.text.DateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.UUID;
import java.util.logging.Logger;

import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;

import cave.nice.testMessage.TestMessageConstants;
import cave.nice.testMessage.data.CannotRetrieveEntitiesException;
import cave.nice.testMessage.data.CannotUpdateEntityException;
import cave.nice.testMessage.data.DataManager;
import cave.nice.testMessage.data.DuplicatedReportingPolicyException;
import cave.nice.testMessage.data.Report;
import cave.nice.testMessage.data.ReportingPolicy;
import cave.nice.testMessage.data.ReportingPolicy.ReportingPolicyType;
import cave.nice.testMessage.data.Test;
import cave.nice.testMessage.data.TestAlreadyAnsweredException;
import cave.nice.testMessage.data.UknownTestChallengeException;
import cave.nice.testMessage.data.UnknownVerifiedAccountException;
import cave.nice.testMessage.data.VerifiedAccount;
import cave.nice.testMessage.data.WrongAccountForTestException;
import cave.nice.testMessage.reports.ReportsGenerator;
import cave.nice.testMessage.reports.ReportsGenerator.ReportType;
import cave.nice.testMessage.reports.ReportsGenerator.ReportingMedium;
import cave.nice.testMessage.templates.TemplateManager;
import cave.nice.testMessage.templates.TemplateManager.TemplateType;

import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.utils.SystemProperty;
import com.google.appengine.api.xmpp.JID;
import com.google.appengine.api.xmpp.MessageBuilder;
import com.google.appengine.api.xmpp.SendResponse;
import com.google.appengine.api.xmpp.XMPPService;
import com.google.appengine.api.xmpp.XMPPServiceFactory;
import com.google.appengine.repackaged.com.google.common.collect.Lists;
import com.google.common.collect.Maps;

@Path("/accounts")
public class VerifiedAccountResource extends Resource {

	private static final Logger LOGGER = Logger
			.getLogger(VerifiedAccountResource.class.getName());

	@Context
	private UriInfo uriInfo;

	@GET
	@Produces(MediaType.APPLICATION_JSON)
	public Response getVerifiedAccounts() throws WebApplicationException {
		DataManager dataManager = getDataManager();
		try {
			return Response.ok(dataManager.getVerifiedAccounts()).build();
		} catch (CannotRetrieveEntitiesException e) {
			// TODO Log error, not return it
			throw new WebApplicationException(Response.serverError().entity(e)
					.build());
		} finally {
			dataManager.close();
		}
	}

	@POST
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	@Path("/{emailAddress}/reportRequest")
	public Response sendReportToUser(
			@PathParam("emailAddress") InternetAddress emailAddress,
			@DefaultValue("HTML") @FormParam("type") String reportTypeString,
			@DefaultValue("GMail") @FormParam("medium") String reportingMediumString) {
		ReportType reportType = ReportType.valueOf(reportTypeString);
		ReportingMedium reportingMedium = ReportingMedium
				.valueOf(reportingMediumString);

		DataManager dataManager = getDataManager();
		try {
			VerifiedAccount account = dataManager
					.getVerifiedAccount(emailAddress);
			List<Test> openTests = dataManager.getOpenTests(account);

			final String report;
			try {
				report = ReportsGenerator.getReport(getCurrentUser(), account,
						openTests, reportType, dataManager.getCurrentTime());
			} catch (Exception e) {
				// TODO Log error
				return Response
						.serverError()
						.entity("Error while generating the report for the account: "
								+ account.getEmailAddress()).build();
			}

			switch (reportingMedium) {
			case GMail: {
				InternetAddress appInternetAddress = null;
				try {
					appInternetAddress = new InternetAddress(
							TestMessageConstants.NOTIFICATIONS_EMAIL_ADDRESS,
							TestMessageConstants.TEST_MESSAGE_SENDER_NAME);
				} catch (UnsupportedEncodingException e) {
					throw new WebApplicationException(e);
				}

				Session session = Session.getDefaultInstance(new Properties(),
						null);

				String notificationMailAddress = getCurrentUser().getEmail();
				try {
					MimeMessage msg = new MimeMessage(session);
					msg.setFrom(appInternetAddress);
					msg.addRecipient(Message.RecipientType.TO,
							new InternetAddress(notificationMailAddress));
					msg.setReplyTo(new InternetAddress[] { appInternetAddress });
					msg.setSubject("Test Message Report for the account '"
							+ account.getEmailAddress() + "'");
					msg.setContent(report, "text/html");

					Transport.send(msg);
				} catch (Exception e) {
					// TODO Log error
					return Response
							.serverError()
							.entity("Error while sending the report to '"
									+ notificationMailAddress + "'").build();
				}

				break;
			}
			case GTalk: {
				JID jid = new JID(getCurrentUser().getEmail());
				com.google.appengine.api.xmpp.Message xmppMessage = new MessageBuilder()
						.withRecipientJids(jid).withBody(report).build();

				XMPPService xmpp = XMPPServiceFactory.getXMPPService();
				SendResponse status = xmpp.sendMessage(xmppMessage);
				boolean messageSent = (status.getStatusMap().get(jid) == SendResponse.Status.SUCCESS);

				if (!messageSent) {
					/*
					 * TODO Retry later?
					 */
					throw new WebApplicationException(
							Response.serverError()
									.entity("Cannot send the report over XMPP for the account '"
											+ emailAddress
											+ "' on the JID '"
											+ jid + "'").build());
				}

				break;
			}
			}

			return Response.noContent().build();
		} catch (UnknownVerifiedAccountException e) {
			throw new WebApplicationException(Response
					.status(Status.NOT_FOUND)
					.entity("No account '" + emailAddress.getAddress()
							+ "' found").build());
		} catch (CannotRetrieveEntitiesException e) {
			throw new WebApplicationException(Response.serverError().entity(e)
					.build());
		} finally {
			dataManager.close();
		}
	}

	@GET
	@Path("/{emailAddress}/report")
	@Produces(MediaType.APPLICATION_JSON)
	public Response getJSONReport(
			@PathParam("emailAddress") InternetAddress emailAddress,
			@QueryParam("since") Date sinceDate) {
		// TODO Implement since
		DataManager dataManager = getDataManager();
		try {
			VerifiedAccount account = dataManager
					.getVerifiedAccount(emailAddress);
			Report report = new Report();
			report.setTimestamp(new Date());
			report.setOpenTests(Lists.newLinkedList(dataManager.getOpenTests(account)));
			report.setClosedTests(Lists.newLinkedList(dataManager.getClosedTests(account)));
			return Response.ok(report).type(MediaType.APPLICATION_JSON).build();
		} catch (UnknownVerifiedAccountException e) {
			throw new WebApplicationException(Response
					.status(Status.NOT_FOUND)
					.entity("No account '" + emailAddress.getAddress()
							+ "' found").build());
		} catch (CannotRetrieveEntitiesException e) {
			throw new WebApplicationException(Response.serverError().entity(e)
					.build());
		} finally {
			dataManager.close();
		}
	}	

	@GET
	@Path("/{emailAddress}/report")
	@Produces(MediaType.TEXT_HTML)
	public Response getHTMLReport(
			@PathParam("emailAddress") InternetAddress emailAddress,
			@QueryParam("since") Date sinceDate) {
		return getTextualReport(emailAddress, sinceDate, MediaType.TEXT_HTML_TYPE);
	}

	@GET
	@Path("/{emailAddress}/report")
	@Produces(MediaType.TEXT_PLAIN)
	public Response getPlainReport(
			@PathParam("emailAddress") InternetAddress emailAddress,
			@QueryParam("since") Date sinceDate) {
		return getTextualReport(emailAddress, sinceDate, MediaType.TEXT_PLAIN_TYPE);
	}

	private Response getTextualReport(InternetAddress emailAddress, Date sinceDate, MediaType mediaType) {
		// TODO Implement since

		ReportType reportType = null;
		if(mediaType == MediaType.TEXT_HTML_TYPE) {
			reportType = ReportType.TEXT_HTML;
		} else if (mediaType == MediaType.TEXT_PLAIN_TYPE) {
			reportType = ReportType.TEXT_PLAIN;
		}

		DataManager dataManager = getDataManager();
		try {
			VerifiedAccount account = dataManager
					.getVerifiedAccount(emailAddress);
			return Response.ok(
					ReportsGenerator.getReport(getCurrentUser(), account,
							dataManager.getOpenTests(account), reportType,
							dataManager.getCurrentTime()), mediaType).build();
		} catch (UnknownVerifiedAccountException e) {
			throw new WebApplicationException(Response
					.status(Status.NOT_FOUND)
					.entity("No account '" + emailAddress.getAddress()
							+ "' found").build());
		} catch (CannotRetrieveEntitiesException e) {
			throw new WebApplicationException(Response.serverError().entity(e)
					.build());
		} finally {
			dataManager.close();
		}
	}

	@PUT
	@Path("/{emailAddress}/tests")
	public void answerTest(
			@PathParam("emailAddress") InternetAddress emailAddress,
			@FormParam("challenge") UUID challenge)
			throws WebApplicationException {
		DataManager dataManager = getDataManager();
		try {
			VerifiedAccount account = dataManager
					.getVerifiedAccount(emailAddress);
			Test test = dataManager.getTestOfAccount(account, challenge);
			dataManager.markTestAsAnswered(test, new Date());
			LOGGER.info("REST answer to the test with challenge '"
					+ test.getChallenge() + "' of the email account '"
					+ account.getEmailAddress() + "'");
		} catch (UknownTestChallengeException e) {
			throw new WebApplicationException(Response
					.status(Status.NOT_FOUND)
					.entity("No test with challenge '" + challenge
							+ "' is found").build());
		} catch (WrongAccountForTestException e) {
			throw new WebApplicationException(Response
					.status(Status.FORBIDDEN)
					.entity("The test with challenge '" + challenge
							+ "' does not belong to the account '"
							+ emailAddress.getAddress() + "'").build());
		} catch (CannotUpdateEntityException e) {
			throw new WebApplicationException(Response.serverError().entity(e)
					.build());
		} catch (UnknownVerifiedAccountException e) {
			throw new WebApplicationException(Response
					.status(Status.NOT_FOUND)
					.entity("No account '" + emailAddress.getAddress()
							+ "' found").build());
		} catch (TestAlreadyAnsweredException e) {
			throw new WebApplicationException(Response
					.status(Status.BAD_REQUEST)
					.entity("The test with challenge '" + challenge
							+ "' has already been answered").build());
		} finally {
			dataManager.close();
		}
	}

	@POST
	@Path("/{emailAddress}/tests")
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	public Response addTest(@Context ServletContext context,
			@PathParam("emailAddress") InternetAddress emailAddress,
			@DefaultValue("true") @FormParam("sendTest") Boolean sendTest)
			throws WebApplicationException {
		UUID challenge = UUID.randomUUID();
		DataManager dataManager = getDataManager();

		try {
			VerifiedAccount account = dataManager
					.getVerifiedAccount(emailAddress);
			Test newTest = dataManager.createTest(account, new Date(),
					challenge);

			if (sendTest) {
				Session session = Session.getDefaultInstance(new Properties(),
						null);
				Message msg = null;
				try {
					InternetAddress appInternetAddress = new InternetAddress(
							TestMessageConstants.TESTS_EMAIL_ADDRESS,
							TestMessageConstants.TEST_MESSAGE_SENDER_NAME);

					Map<String, Object> params = Maps.newHashMap();
					params.put("challenge", newTest.getChallenge());
					params.put(
							"url",
							"http://"
									+ SystemProperty.applicationId.get()
									+ ".appspot.com/answerTest.jsp?emailAddress="
									+ account.getEmailAddress() + "&challenge="
									+ newTest.getChallenge());

					String content = TemplateManager.getInstance(context)
							.applyTemplate(TemplateType.TEST_MESSAGE, params);

					msg = new MimeMessage(session);
					msg.setFrom(appInternetAddress);
					msg.addRecipient(Message.RecipientType.TO,
							account.getInternetAddress());
					msg.setReplyTo(new InternetAddress[] { appInternetAddress });
					msg.addHeader(
							TestMessageConstants.SMTP_HEADER_ACCOUNT_IDENTIFIER,
							KeyFactory.keyToString(account.getIdentifier()));
					msg.addHeader(
							TestMessageConstants.SMTP_HEADER_TEST_IDENTIFIER,
							KeyFactory.keyToString(newTest.getIdentifier()));
					msg.setSubject("Test Message on "
							+ DateFormat.getInstance()
									.format(newTest.getDate()));
					msg.setContent(content, "text/plain");
					Transport.send(msg);
				} catch (Exception e) {
					/*
					 * Remove the test that was not successfully sent
					 */
					dataManager.removeTest(newTest);

					throw new WebApplicationException(
							Response.serverError()
									.entity("Error while sending the following test message to '"
											+ account.getEmailAddress()
											+ "': "
											+ msg).entity(e).build());
				}
			}

			URI newEntityURI = uriInfo.getBaseUri().resolve(
					"/resources/accounts/" + emailAddress.getAddress()
							+ "/tests/" + challenge);

			return Response.created(newEntityURI).build();
		} catch (UnknownVerifiedAccountException e) {
			throw new WebApplicationException(Response
					.status(Status.NOT_FOUND)
					.entity("No account '" + emailAddress.getAddress()
							+ "' found").build());
		} finally {
			dataManager.close();
		}
	}

	@GET
	@Path("/{emailAddress}/tests")
	@Produces(MediaType.APPLICATION_JSON)
	public List<Test> getAllTests(
			@PathParam("emailAddress") InternetAddress emailAddress)
			throws WebApplicationException {
		DataManager dataManager = getDataManager();
		try {
			VerifiedAccount account = dataManager
					.getVerifiedAccount(emailAddress);

			return Lists.newArrayList(account.getTests());
		} catch (UnknownVerifiedAccountException e) {
			throw new WebApplicationException(Response
					.status(Status.NOT_FOUND)
					.entity("No account '" + emailAddress.getAddress()
							+ "' found").build());
		} finally {
			dataManager.close();
		}
	}

	@GET
	@Path("/{emailAddress}/closedTests")
	@Produces(MediaType.APPLICATION_JSON)
	public List<Test> getClosedTests(
			@PathParam("emailAddress") InternetAddress emailAddress)
			throws WebApplicationException {
		DataManager dataManager = getDataManager();
		try {
			VerifiedAccount account = dataManager
					.getVerifiedAccount(emailAddress);
			// checkAuthentication(userOwnerOf(account).or(userIsAdministrator()));

			return Lists.newArrayList(dataManager.getClosedTests(account));
		} catch (CannotRetrieveEntitiesException e) {
			throw new WebApplicationException(
					Response.serverError()
							.entity("Error while retrieving the closed tests of the account '"
									+ emailAddress.getAddress() + "'")
							.entity(e).build());
		} catch (UnknownVerifiedAccountException e) {
			throw new WebApplicationException(Response
					.status(Status.NOT_FOUND)
					.entity("No account '" + emailAddress.getAddress()
							+ "' found").build());
		} finally {
			dataManager.close();
		}
	}

	@GET
	@Path("/{emailAddress}/openTests")
	@Produces(MediaType.APPLICATION_JSON)
	public List<Test> getOpenTests(
			@PathParam("emailAddress") InternetAddress emailAddress)
			throws WebApplicationException {
		DataManager dataManager = getDataManager();

		try {
			VerifiedAccount account = dataManager
					.getVerifiedAccount(emailAddress);

			return Lists.newArrayList(dataManager.getOpenTests(account));
		} catch (CannotRetrieveEntitiesException e) {
			throw new WebApplicationException(
					Response.serverError()
							.entity("Error while retrieving the open tests of the account '"
									+ emailAddress.getAddress() + "'")
							.entity(e).build());
		} catch (UnknownVerifiedAccountException e) {
			throw new WebApplicationException(Response
					.status(Status.NOT_FOUND)
					.entity("No account '" + emailAddress.getAddress()
							+ "' found").build());
		} finally {
			dataManager.close();
		}
	}

	@DELETE
	@Path("/{emailAddress}/tests/{challenge}")
	public Response deleteTest(
			@PathParam("emailAddress") InternetAddress emailAddress,
			@PathParam("challenge") UUID challenge)
			throws WebApplicationException {
		DataManager dataManager = getDataManager();
		try {
			VerifiedAccount account = dataManager
					.getVerifiedAccount(emailAddress);

			Test test = dataManager.getTestOfAccount(account, challenge);
			dataManager.removeTest(test);
			return Response.ok().build();
		} catch (UknownTestChallengeException e) {
			throw new WebApplicationException(Response
					.status(Status.NOT_MODIFIED)
					.entity("No test with challenge '" + challenge + "' found")
					.build());
		} catch (WrongAccountForTestException e) {
			throw new WebApplicationException(Status.FORBIDDEN);
		} catch (UnknownVerifiedAccountException e) {
			throw new WebApplicationException(Response
					.status(Status.NOT_FOUND)
					.entity("No account '" + emailAddress.getAddress()
							+ "' found").build());
		} finally {
			dataManager.close();
		}
	}

	@POST
	@Path("/{emailAddress}/reportingPolicies/withMethodOverride")
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	public Response processMethodOvveride(
			@PathParam("emailAddress") InternetAddress emailAddress,
			@FormParam("_method") String method,
			@FormParam("type") ReportingPolicyType type,
			@FormParam("notifyAfterMinutes") Integer notifyAfterMinutes,
			@FormParam("notifyIfNoOpenTests") Boolean notifyIfNoOpenTests)
			throws WebApplicationException {
		if(method == null) {
			throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("Required parameter '_method' not provided").build());
		}

		String methodLC = method.toLowerCase();
		if(methodLC.equals("put")) {
			return updateReportingPolicy(emailAddress, type, notifyAfterMinutes, notifyIfNoOpenTests);
		}

		throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("Unrecognize value for the parameter '_method': " + method).build());
	}

	@POST
	@Path("/{emailAddress}/reportingPolicies")
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	public Response addReportingPolicy(
			@PathParam("emailAddress") InternetAddress emailAddress,
			@FormParam("type") ReportingPolicyType type,
			@FormParam("notifyAfterMinutes") Integer notifyAfterMinutes,
			@FormParam("notifyIfNoOpenTests") Boolean notifyIfNoOpenTests)
			throws WebApplicationException {
		if (type == null) {
			throw new WebApplicationException(Response
					.status(Status.BAD_REQUEST)
					.entity("Required parameter 'type' not provided").build());
		}

		if (notifyAfterMinutes == null) {
			throw new WebApplicationException(
					Response.status(Status.BAD_REQUEST)
							.entity("Required parameter 'notifyAfterMinutes' not provided")
							.build());
		}

		if (notifyIfNoOpenTests == null) {
			throw new WebApplicationException(
					Response.status(Status.BAD_REQUEST)
							.entity("Required parameter 'notifyIfNoOpenTests' not provided")
							.build());
		}

		DataManager dataManager = getDataManager();
		try {
			VerifiedAccount account = dataManager
					.getVerifiedAccount(emailAddress);

			// First, check if a policy of the selected type exists, If so, we
			// update it
			for (ReportingPolicy reportingPolicy : account
					.getReportingPolicies()) {
				if (type.equals(reportingPolicy.getType())) {
					throw new WebApplicationException(Status.CONFLICT);
				}
			}

			dataManager.addNewReportingPolicy(account, type,
					notifyAfterMinutes, notifyIfNoOpenTests);

			URI newEntityURI = uriInfo.getBaseUri().resolve(
					"/resources/accounts/" + emailAddress.getAddress()
							+ "/reportingPolicies/" + type);

			return Response.created(newEntityURI).build();
		} catch (UnknownVerifiedAccountException e) {
			throw new WebApplicationException(Response
					.status(Status.NOT_FOUND)
					.entity("No account '" + emailAddress.getAddress()
							+ "' found").build());
		} catch (DuplicatedReportingPolicyException e) {
			throw new WebApplicationException(Response.status(Status.CONFLICT)
					.entity(e.getMessage()).build());
		} finally {
			dataManager.close();
		}
	}

	@PUT
	@Path("/{emailAddress}/reportingPolicies/{type}")
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	public Response updateReportingPolicy(
			@PathParam("emailAddress") InternetAddress emailAddress,
			@PathParam("type") ReportingPolicyType type,
			@FormParam("notifyAfterMinutes") Integer notifyAfterMinutes,
			@FormParam("notifyIfNoOpenTests") Boolean notifyIfNoOpenTests)
			throws WebApplicationException {
		/*
		if (type == null) {
			throw new WebApplicationException(Response
					.status(Status.BAD_REQUEST)
					.entity("Required parameter 'type' not provided").build());
		}
		*/

		DataManager dataManager = getDataManager();
		try {
			VerifiedAccount account = dataManager
					.getVerifiedAccount(emailAddress);

			// First, check if a policy of the selected type exists, If so, we
			// update it
			ReportingPolicy reportingPolicy = account.getReportingPolicy(type);
			boolean modified = false;
			if (notifyAfterMinutes != null && reportingPolicy.getNotifyAfterMinutes() != notifyAfterMinutes) {
				reportingPolicy.setNotifyAfterMinutes(notifyAfterMinutes);
				modified = true;
			}
			if (notifyIfNoOpenTests != null && reportingPolicy.isNotifyIfNoOpenTests() != notifyIfNoOpenTests) {
				reportingPolicy.setNotifyIfNoOpenTests(notifyIfNoOpenTests);
				modified = true;
			}

			if (modified) {
				return Response.status(Status.OK).build();
			}

			return Response.status(Status.NOT_MODIFIED).build();
		} catch (NoSuchElementException e) {
			throw new WebApplicationException(Status.NOT_FOUND);
		} catch (UnknownVerifiedAccountException e) {
			throw new WebApplicationException(Response
					.status(Status.NOT_FOUND)
					.entity("No account '" + emailAddress.getAddress()
							+ "' found").build());
		} finally {
			dataManager.close();
		}
	}

	/*
	 * @PUT
	 * 
	 * @Path("/{emailAddress}/reportingPolicies/{type}/notifyAfterMinutes")
	 * 
	 * @Consumes(MediaType.APPLICATION_FORM_URLENCODED) public Response
	 * updateReportingPolicy(
	 * 
	 * @PathParam("emailAddress") InternetAddress emailAddress,
	 * 
	 * @PathParam("type") ReportingPolicyType type,
	 * 
	 * @FormParam("notifyAfterMinutes") Integer notifyAfterMinutes) throws
	 * WebApplicationException { if(notifyAfterMinutes == null) { throw new
	 * WebApplicationException(Response.status(Status.BAD_REQUEST).entity(
	 * "Required parameter 'notifyAfterMinutes' not provided").build()); }
	 * 
	 * DataManager dataManager = getDataManager(); try { VerifiedAccount account
	 * = dataManager .getVerifiedAccount(emailAddress);
	 * 
	 * // First, check if a policy of the selected type exists, If so, we //
	 * update it ReportingPolicy reportingPolicy =
	 * account.getReportingPolicy(type); if
	 * (reportingPolicy.getNotifyAfterMinutes() != notifyAfterMinutes) {
	 * reportingPolicy.setNotifyAfterMinutes(notifyAfterMinutes); return
	 * Response.status(Status.OK).build(); }
	 * 
	 * return Response.status(Status.NOT_MODIFIED).build(); } catch
	 * (NoSuchElementException e) { throw new
	 * WebApplicationException(Status.NOT_FOUND); } catch
	 * (UnknownVerifiedAccountException e) { throw new
	 * WebApplicationException(Response .status(Status.NOT_FOUND)
	 * .entity("No account '" + emailAddress.getAddress() + "' found").build());
	 * } finally { dataManager.close(); } }
	 * 
	 * @PUT
	 * 
	 * @Path("/{emailAddress}/reportingPolicies/{type}/notifyIfNoOpenTests")
	 * 
	 * @Consumes(MediaType.APPLICATION_FORM_URLENCODED) public Response
	 * updateReportingPolicy(
	 * 
	 * @PathParam("emailAddress") InternetAddress emailAddress,
	 * 
	 * @PathParam("type") ReportingPolicyType type,
	 * 
	 * @FormParam("notifyIfNoOpenTests") Boolean notifyIfNoOpenTests) throws
	 * WebApplicationException { if(notifyIfNoOpenTests == null) { throw new
	 * WebApplicationException(Response.status(Status.BAD_REQUEST).entity(
	 * "Required parameter 'notifyIfNoOpenTests' not provided").build()); }
	 * 
	 * DataManager dataManager = getDataManager(); try { VerifiedAccount account
	 * = dataManager .getVerifiedAccount(emailAddress);
	 * 
	 * // First, check if a policy of the selected type exists, If so, we //
	 * update it ReportingPolicy reportingPolicy =
	 * account.getReportingPolicy(type); if
	 * (reportingPolicy.isNotifyIfNoOpenTests() != notifyIfNoOpenTests) {
	 * reportingPolicy.setNotifyIfNoOpenTests(notifyIfNoOpenTests); return
	 * Response.status(Status.OK).build(); }
	 * 
	 * return Response.status(Status.NOT_MODIFIED).build(); } catch
	 * (NoSuchElementException e) { throw new
	 * WebApplicationException(Status.NOT_FOUND); } catch
	 * (UnknownVerifiedAccountException e) { throw new
	 * WebApplicationException(Response .status(Status.NOT_FOUND)
	 * .entity("No account '" + emailAddress.getAddress() + "' found").build());
	 * } finally { dataManager.close(); } }
	 */

	@GET
	@Path("/{emailAddress}/reportingPolicies")
	@Produces(MediaType.APPLICATION_JSON)
	public Response getReportingPolicies(
			@PathParam("emailAddress") InternetAddress emailAddress)
			throws WebApplicationException {
		DataManager dataManager = getDataManager();
		try {
			VerifiedAccount account = dataManager
					.getVerifiedAccount(emailAddress);

			List<ReportingPolicy> reportingPolicies = Lists
					.newArrayList(account.getReportingPolicies());

			return Response.ok(reportingPolicies).build();
		} catch (UnknownVerifiedAccountException e) {
			throw new WebApplicationException(Response
					.status(Status.NOT_FOUND)
					.entity("No account '" + emailAddress.getAddress()
							+ "' found").build());
		} finally {
			dataManager.close();
		}
	}

	@DELETE
	@Path("/{emailAddress}/reportingPolicies")
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	public Response deleteReportingPolicy(
			@PathParam("emailAddress") InternetAddress emailAddress,
			@FormParam("type") ReportingPolicyType type)
			throws WebApplicationException {
		DataManager dataManager = getDataManager();
		try {
			VerifiedAccount account = dataManager
					.getVerifiedAccount(emailAddress);

			ReportingPolicy reportingPolicy = account.getReportingPolicy(type);
			dataManager.removeReportingPolicy(account, reportingPolicy);
			return Response.status(Status.NO_CONTENT).build();
		} catch (UnknownVerifiedAccountException e) {
			throw new WebApplicationException(Response
					.status(Status.NOT_FOUND)
					.entity("No account '" + emailAddress.getAddress()
							+ "' found").build());
		} catch (NoSuchElementException e) {
			throw new WebApplicationException(Response
					.status(Status.NOT_FOUND)
					.entity("No reporting policy of type '" + type
							+ "' found for the account '"
							+ emailAddress.getAddress() + "'").build());
		} finally {
			dataManager.close();
		}
	}

	@DELETE
	@Path("/{emailAddress}")
	public Response deleteAccount(
			@PathParam("emailAddress") InternetAddress emailAddress)
			throws WebApplicationException {
		DataManager dataManager = getDataManager();
		try {
			VerifiedAccount account = dataManager
					.getVerifiedAccount(emailAddress);

			dataManager.removeAccount(account);
			return Response.status(Status.NO_CONTENT).build();
		} catch (UnknownVerifiedAccountException e) {
			throw new WebApplicationException(Response
					.status(Status.NOT_FOUND)
					.entity("No account '" + emailAddress.getAddress()
							+ "' found").build());
		} finally {
			dataManager.close();
		}
	}

}
